package com.yiba.vpn.utils.logger;

import android.util.Log;


import java.io.File;
import java.security.InvalidParameterException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class LogUtil {

    /**
     * true:打开log  false:关闭所有的日志
     */
    public static boolean OPEN_LOG = true  ;

    /**
     * TAG 名称
     */
    private static String tag = "yiba_vpn";
    private String mClassName;
    private static LogUtil log;
    private static final String USER_NAME = "@tool@";
    private static int sLogLevel = Log.INFO;//默认标记

    private LogUtil(String name) {
        mClassName = name;
    }

    /**
     * Get The Current Function Name
     *
     * @return Name
     */
    private String getFunctionName() {
        StackTraceElement[] sts = Thread.currentThread().getStackTrace();
        if (sts == null) {
            return null;
        }
        for (StackTraceElement st : sts) {
            if (st.isNativeMethod()) {
                continue;
            }
            if (st.getClassName().equals(Thread.class.getName())) {
                continue;
            }
            if (st.getClassName().equals(this.getClass().getName())) {
                continue;
            }
            return mClassName + "[ " + Thread.currentThread().getName() + ": "
                    + st.getFileName() + ":" + st.getLineNumber() + " "
                    + st.getMethodName() + " ]";
        }
        return null;
    }

    public static void i(Object str) {
        print(Log.INFO, str);
    }

    public static void d(Object str) {
        print(Log.DEBUG, str);
    }

    public static void v(Object str) {
        print(Log.VERBOSE, str);
    }

    public static void w(Object str) {
        print(Log.WARN, str);
    }

    public static void e(Object str) {
        print(Log.ERROR, str);
    }

    /**
     * 用于区分不同接口数据 打印传入参数
     *
     * @param index
     * @param str
     */

    private static void print(int index, Object str) {
        if (!OPEN_LOG) {
            return;
        }
        if (log == null) {
            log = new LogUtil(USER_NAME);
        }
        String name = log.getFunctionName();
        if (name != null) {
            str = name + " - " + str;
        }
        Log.i("index",index+" == "+ str);
        switch (index) {
            case Log.VERBOSE:
                Log.v(tag, str.toString());
                writeToFileIfNeeded(tag, str.toString(), Log.VERBOSE);
                break;
            case Log.DEBUG:
                Log.d(tag, str.toString());
                writeToFileIfNeeded(tag, str.toString(), Log.DEBUG);
                break;
            case Log.INFO:
                Log.i(tag, str.toString());
                writeToFileIfNeeded(tag, str.toString(), Log.INFO);
                break;
            case Log.WARN:
                Log.w(tag, str.toString());
                writeToFileIfNeeded(tag, str.toString(), Log.WARN);
                break;
            case Log.ERROR:
                Log.e(tag, str.toString());
                writeToFileIfNeeded(tag, str.toString(), Log.ERROR);
                break;
            default:
                break;
        }
    }
    //-----------------------------------增加日志持久化功能------------------------------------------
    private static final int CACHE_QUEUE_SIZE = 10; //缓存最多10条log信息后输出到文件
    private static final SimpleDateFormat LOG_DATE_TIME_FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");

    private static ExecutorService sLogExecutor = Executors.newSingleThreadExecutor();
    private static Queue<String> sMsgQueue = new ArrayBlockingQueue<>(CACHE_QUEUE_SIZE);
    private static LogFileManager sLogFileManager;
    /**
     * 设置写入log的文件夹
     *
     * @param dirPath 文件夹地址
     */
    public static void setLogDir(String dirPath) {
        File file = new File(dirPath);
        if (!file.exists() || !file.isDirectory()) {
            throw new InvalidParameterException();
        }
        sLogFileManager = new LogFileManager(dirPath);
    }

    /**
     * 程序退出时调用该方法
     *
     * @param
     */
    public static void close() {
        if (sLogFileManager != null) {
            sLogExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    flushLogToFile();
                }
            });
        }
    }
    private static void writeToFileIfNeeded(final String tag, final String msg, int logLevel) {
        if (logLevel < sLogLevel || sLogFileManager == null) {
            return;
        }
        sLogExecutor.execute(new Runnable() {
            @Override
            public void run() {
                appendLog(tag, msg);
            }
        });
    }

    private static void appendLog(String tag, String msg) {
        String logMsg = formatLog(tag, msg);
        sMsgQueue.add(logMsg);
        // 到达缓存上限，写到文件中
        if (sMsgQueue.size() >= CACHE_QUEUE_SIZE) {
            flushLogToFile();
        }
    }

    private static void flushLogToFile() {
        StringBuilder stringBuilder = new StringBuilder();
        for (String message : sMsgQueue) {
            stringBuilder.append(message);
        }
        sLogFileManager.writeLogToFile(stringBuilder.toString());
        sMsgQueue.clear();
    }

    private static String formatLog(String tag, String msg) {
        return String.format("%s pid=%d %s: %s\n", LOG_DATE_TIME_FORMAT.format(new Date()), android.os.Process.myPid(), tag, msg);
    }
}
